package com.pan.thread;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 创建一个线程池
 *
 * 不建议直击使用Excutors进行创建线程池
 * CachedThreadPool可能创建过多线程
 * 队列可能会满，造成内存溢出
 *
 */
@Slf4j
public class HousePool {


    /**
     * 不限数量创建线程，最多创建Integer.max个线程
     */
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

    /**
     * 创建固定数量线程池
     */
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

    /**
     * 单线程池
     */
    ExecutorService singleThread = Executors.newSingleThreadExecutor();

    /**
     * 定时任务线程池
     */
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

    /**
     * 自定义线程池
     * 1、核心线程数 -->理论上讲用户线程数可以无限多，主要受机器内存影响
     * 2、最大线程数
     * 3、超过核心线程的空闲存活时间
     * 4、时间单位
     * 5、阻塞队列
     *     LinkedBlockingQueue-->如果不限定数量则是一个无界队列，可能会引起内存溢出（OOM:OUT OF MEMEORY）
     *     ArrayBlockingQueue -->有界队列
     *     PriorityBlockingQueue -->有界优先队列
     *     SynchronousQueue -->只能存放一个元素
     * 6、线程工厂
     * 7、拒绝策略
     *     ThreadPoolExecutor.AbortPolicy
     *     ThreadPoolExecutor.CallerRunsPolicy
     *     ThreadPoolExecutor.DiscardOldestPolicy
     *     ThreadPoolExecutor.DiscardPolicy
     */
    ExecutorService myselfHorsePool = new ThreadPoolExecutor(5, 10, 10, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(100), new ThreadFactory() {

        SecurityManager s = System.getSecurityManager();
        private final ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String  threadNamePrefix = "myselfHorsePool-horse-";
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(group,r,threadNamePrefix+threadNumber.getAndIncrement(),0);
            return thread;
        }

    },new ThreadPoolExecutor.DiscardOldestPolicy());

    /**
     * 有多少个任务，则一次创建多少个线程
     * 从日志可以看出一共创建了10个线程
     * These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks
     */
    public void useCacheThreadPool(){
        log.info("-----------------{}---{}-------------------------","useCacheThreadPool","start");
        HorseRunnable horseRunnable = new HorseRunnable();
        for (int i = 0; i < 10; i++) {
            cachedThreadPool.submit(horseRunnable);
        }
        cachedThreadPool.shutdown();
    }

    /**
     * 每次只启动固定数量的线程
     * 如果没有线程则阻塞等待
     */
    public void useFixedThreadPool(){
        log.info("-----------------{}---{}-------------------------","useFixedThreadPool","start");
        HorseRunnable horseRunnable = new HorseRunnable();
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.submit(horseRunnable);
        }
        fixedThreadPool.shutdown();
    }

    /**
     * 每次只启动一个线程执行任务
     */
    public void useSingleThread(){
        log.info("-----------------{}---{}-------------------------","useSingleThread","start");
        HorseRunnable horseRunnable = new HorseRunnable();
        for (int i = 0; i < 10; i++) {
            singleThread.submit(horseRunnable);
        }
        singleThread.shutdown();
    }

    /**
     * 定时任务
     * 初始延迟1s,后期每次延迟3s
     */
    public void useScheduledThreadPool(){
        log.info("-----------------{}---{}-------------------------","useScheduledThreadPool","start");
        HorseRunnable horseRunnable = new HorseRunnable();
        scheduledThreadPool.scheduleAtFixedRate(horseRunnable,1,3,TimeUnit.MILLISECONDS);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            scheduledThreadPool.shutdown();
        }
    }

    /**
     * 启动自定义线程池
     */
    public void useMyselfHorsePool(){
        log.info("-----------------{}---{}-------------------------","useMyselfHorsePool","start");
        HorseRunnable horseRunnable = new HorseRunnable();
        for (int i = 0; i < 10; i++) {
            myselfHorsePool.submit(horseRunnable);
        }

        myselfHorsePool.shutdown();
    }

    public void useHorsePoolCallable() throws ExecutionException, InterruptedException {

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        log.info("-----------------{}---{}-------------------------","useMySelfHorsePoolCallable","start");
        HorseCallable horseCallable = new HorseCallable();
        List<Future> resultList  = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Future resultFuture = cachedThreadPool.submit(horseCallable);
            resultList.add(resultFuture);
        }
        for (Future future : resultList) {
            Object callable = future.get();
            log.info("callable:{}",callable);
        }
        cachedThreadPool.shutdown();
    }

    public void runRunnable(HousePool housePool){
        int number =0;
        try {
            Thread.sleep(1000);
            housePool.useCacheThreadPool();

            /*
                通过循环调用来查看前一个线程池是否已经执行完毕
             */
            while(true){
                if(housePool.cachedThreadPool.isTerminated()&&number==0) {
                    housePool.useSingleThread();
                    number++;
                    Thread.sleep(2000);
                }else if(housePool.singleThread.isTerminated()&&number==1) {
                    housePool.useScheduledThreadPool();
                    number++;
                    Thread.sleep(2000);
                }else if(housePool.scheduledThreadPool.isTerminated()&&number==2) {
                    housePool.useFixedThreadPool();
                    number++;
                    Thread.sleep(2000);
                }else if(housePool.fixedThreadPool.isTerminated()&&number==3) {
                    housePool.useMyselfHorsePool();
                    number++;
                    Thread.sleep(2000);
                }else if(housePool.myselfHorsePool.isTerminated()) {
                    break;
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void runCallable(HousePool housePool){
        try {
            housePool.useHorsePoolCallable();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 执行不同类型线程池的submit方法
     * 一个线程池可以同时执行实现runnable接口的方法和实现callable接口的方法
     * @param args
     */
    public static void main(String[] args) {

        HousePool housePool =new HousePool();
        housePool.runRunnable(housePool);
        housePool.runCallable(housePool);
    }

}
